/*********************************************************************
*                SEGGER Microcontroller GmbH & Co. KG                *
*        Solutions for real time microcontroller applications        *
**********************************************************************
*                                                                    *
*        (c) 1996 - 2017  SEGGER Microcontroller GmbH & Co. KG       *
*                                                                    *
*        Internet: www.segger.com    Support:  support@segger.com    *
*                                                                    *
**********************************************************************

** emWin V5.46 - Graphical user interface for embedded applications **
emWin is protected by international copyright laws.   Knowledge of the
source code may not be used to write a similar product.  This file may
only  be used  in accordance  with  a license  and should  not be  re-
distributed in any way. We appreciate your understanding and fairness.
----------------------------------------------------------------------
File    : SWIPELIST_Demo.c
Purpose : Demonstrate the SWIPELIST Widget and ANIMATION module of
          emWin. Presenting different SEGGER products.
--------  END-OF-HEADER  ---------------------------------------------
*/

#include <stdlib.h>
#include "DIALOG.h"
#include "SWIPELIST.h"

//
// Choose proper bitmaps depending on color format
//
extern GUI_CONST_STORAGE GUI_BITMAP bmBackgroundWindow_480x272;
extern GUI_CONST_STORAGE GUI_BITMAP bmBackground_480x272;
extern GUI_CONST_STORAGE GUI_BITMAP bmSeparator_218x21;
extern GUI_CONST_STORAGE GUI_BITMAP bmIcon_Production_64x64;
extern GUI_CONST_STORAGE GUI_BITMAP bmIcon_OS_64x64;
extern GUI_CONST_STORAGE GUI_BITMAP bmIcon_JLink_64x64;
extern GUI_CONST_STORAGE GUI_BITMAP bmIcon_GUI_64x64;
extern GUI_CONST_STORAGE GUI_BITMAP bmIcon_FS_64x64;
extern GUI_CONST_STORAGE GUI_BITMAP bmIcon_Cpp_64x64;
extern GUI_CONST_STORAGE GUI_BITMAP bmIcon_Connectivity_64x64;
extern GUI_CONST_STORAGE GUI_BITMAP bmIcon_Compress_64x64;
extern GUI_CONST_STORAGE GUI_BITMAP bmIcon_Cloud_SSL_64x64;
extern GUI_CONST_STORAGE GUI_BITMAP bmIcon_BootLoader_64x64;

#define BM_BACKGROUND_WIN bmBackgroundWindow_480x272
#define BM_BACKGROUND     bmBackground_480x272
#define BM_SEPARATOR      bmSeparator_218x21
#define BM_PRODUCTION     bmIcon_Production_64x64
#define BM_OS             bmIcon_OS_64x64
#define BM_JLINK          bmIcon_JLink_64x64
#define BM_GUI            bmIcon_GUI_64x64
#define BM_FS             bmIcon_FS_64x64
#define BM_CPP            bmIcon_Cpp_64x64
#define BM_CONNECT        bmIcon_Connectivity_64x64
#define BM_COMPRESS       bmIcon_Compress_64x64
#define BM_SECURITY       bmIcon_Cloud_SSL_64x64
#define BM_BOOTLOAD       bmIcon_BootLoader_64x64

//
// Define fonts for easy exchange
//
#define FONT_REG   GUI_Font16_1
#define FONT_BOLD  GUI_Font16B_1
//
// ID defines for identification
//
#define ID_BUTTON_0             (GUI_ID_USER + 0x01)
#define ID_SWIPELIST_0          (GUI_ID_USER + 0x02)
#define ID_SWIPELIST_ITEM_0     (GUI_ID_USER + 0x03)
//
// Color definitions, macro converts them depending on color format
//
#define COLOR_GREEN      GUI_MAKE_COLOR(0x0014b6a9)
#define COLOR_BLUE       GUI_MAKE_COLOR(0x00623700)
#define COLOR_LIGHTBLUE  GUI_MAKE_COLOR(0x00aa7d67)
#define COLOR_WHITE      GUI_MAKE_COLOR(0x00F2F2F2)
#define COLOR_LEMON      GUI_MAKE_COLOR(0x0000d6d3)
#define COLOR_CPP        GUI_MAKE_COLOR(0x0035048c)
#define COLOR_JLINK      GUI_MAKE_COLOR(0x002d27c1)
#define COLOR_OS         GUI_MAKE_COLOR(0x00275bea)
#define COLOR_FS         GUI_MAKE_COLOR(0x002292f3)
#define COLOR_COMPR      GUI_MAKE_COLOR(0x003caff8)
#define COLOR_BOOTLOAD   GUI_MAKE_COLOR(0x0000d7d3)
#define COLOR_CONNECT    GUI_MAKE_COLOR(0x0000bdeb)
#define COLOR_SECURITY   GUI_MAKE_COLOR(0x0000bdeb)
#define COLOR_GUI        GUI_MAKE_COLOR(0x0000c7db)
#define COLOR_PRODUCTION GUI_MAKE_COLOR(0x001ac39d)
//
// Y-Size of separators and items
//
#define SWIPE_SEPERATOR_SIZE  20
#define SWIPE_ITEM_SIZE       35
//
// Index values for separators
//
#define SWIPE_SEP_INDEX0         0
#define SWIPE_SEP_INDEX1         1
#define SWIPE_SEP_INDEX2         2
#define SWIPE_SEP_INDEX3         3
//
// IDs for items
//
#define SWIPE_ITEM_ID0         0 
#define SWIPE_ITEM_ID1         1 
#define SWIPE_ITEM_ID2         2 
#define SWIPE_ITEM_ID3         3 
#define SWIPE_ITEM_ID4         4 
#define SWIPE_ITEM_ID5         5 
#define SWIPE_ITEM_ID6         6 
#define SWIPE_ITEM_ID7         7 
#define SWIPE_ITEM_ID8         8 
#define SWIPE_ITEM_ID9         9 
#define SWIPE_ITEM_ID10        10
#define SWIPE_ITEM_ID11        11
#define SWIPE_ITEM_ID12        12
#define SWIPE_ITEM_ID13        13
#define SWIPE_ITEM_ID14        14
#define SWIPE_ITEM_ID15        15
#define SWIPE_ITEM_ID16        16

//
// Define some names for the separator items
//
static char * _aTextSeparator[] = {
  "Developing Software",
  "Debug Probes",
  "Middleware",
  "Production",
};

//
// This are the different entries below the seperators
//
static char * _aTextHeader[] = {
  //
  // Developing Software
  //
  "Embedded Studio",
  "SystemView",
  "J-Link Debugger",
  //
  // Debug Probes
  //
  "J-Link/J-Trace",
  //
  // Middleware
  //
  "embOS",
  "emFile",
  "emUSB Device/Host",
  "emCompress",
  "embOS/IP",
  "emSecure",
  "emSSL",
  "emWin",
  //
  // Production
  //
  "Flasher"
};

typedef struct {
  char             * pHeadline;
  const GUI_BITMAP * pBitmap;
  GUI_COLOR          Color;
} ITEM_INFO;

//
// Description of the entries above
//
static ITEM_INFO _aItemInfo[] = {
  { "Embedded Studio",   &BM_CPP,        COLOR_CPP},
  { "SystemView",        &BM_CPP,        COLOR_CPP},
  { "J-Link Debugger",   &BM_CPP,        COLOR_CPP},
  { "J-Link/J-Trace",    &BM_JLINK,      COLOR_JLINK},
  { "embOS",             &BM_OS,         COLOR_OS},
  { "emFile",            &BM_FS,         COLOR_FS},
  { "emUSB Device/Host", &BM_CONNECT,    COLOR_CONNECT},
  { "emCompress",        &BM_COMPRESS,   COLOR_COMPR},
  { "embOS/IP",          &BM_CONNECT,    COLOR_CONNECT},
  { "emSecure",          &BM_SECURITY,   COLOR_SECURITY},
  { "emSSL",             &BM_SECURITY,   COLOR_SECURITY},
  { "emWin",             &BM_GUI,        COLOR_GUI},
  { "Flasher",           &BM_PRODUCTION, COLOR_PRODUCTION}
};

//
// Description for different products
//
static char * _aDescription[] = {
  "- Free for Education\n- Cross-Platform Support\n- Target Support\n- Powerful Project Manager\n- Compiler included\n- Feature-packed Debugger\n- First-Class Editor",
  "- Minimal intrusive\n- Free tool\n- No license costs\n- RTOS tracing\n- Interrupt tracing\n- Real-time recording\n- Live analysis of captured data\n- Works on any CPU.\n",
  "- C code source level debugging\n- Assembly instruction debugging\n- High-speed programming of\n  the application into the target\n- Fully customizable windows\n- Debug Information Windows\n  for any purpose\n- Direct use of J-Link features",
  "- Over 400,000 units sold\n- Up to 3 MB/s Download speed\n- Multi core debugging\n- All CPU families supported\n- Internal trace buffer supported\n- Multiple target interfaces\n  (JTAG, SWD, FINE, SPD, ...)",
  "- Available for all popular cores,\n  compiler and development tools\n- Kernel awareness plugins\n- Unlimited number of tasks\n  and priorities\n- Power management\n- Precise time measurement\n- Zero latency interrupts",
  "- Windows-compatible FAT12,\n  FAT16 and FAT32 support\n- Long file name support\n- Multiple device driver support\n- Multiple media support\n- NOR- and NAND-flash driver\n- RAID 1 support",
  "- Optimized for embOS but\n  works even without RTOS\n- No custom USB host driver necessary\n- Hardware abstraction layer\n  allows rapid addition of support\n  for new devices\n- Runs out-of-the-box",
  "- Highly efficient compression\n- Small decompressor ROM\n  footprint\n- Fixed decompressor RAM use\n- Wide range of codecs\n- Automatic selection of best\n  codec for each file\n- Royalty free",
  "- High performance\n- Small footprint\n- Runs out-of-the-box\n- No configuration required\n- Works with any RTOS\n- Zero data copy for\n  ultra fast performance\n- PPP/PPPOE available",
  "- Asymmetric algorithms\n- Different algorithms available\n- Hardware-independent\n- High performance,\n  small memory footprint\n- Applicable for new and\n  existing products\n- Full source code",
  "- Secures your connection\n- Compatible with any server\n- Easy to understand\n- Simple to integrate\n- No additional hardware required\n- No royalties",
  "- Any CPU\n- Any LCD and LCD-controller\n- Works without LCD\n- Wide range of PC tools\n- Routines are optimized for speed and size\n- Small memory footprint\n- Highly configurable",
  "- Stand-alone JTAG/SWD\n  programmer\n- Non-authorized access\n  protection\n- Wide range of supported CPUs\n- Power over USB\n- Portable version\n- Ethernet interface"
};

//
// Animation data structure
//
typedef struct {
  WM_HWIN hWin;
  int Dir;
} ANIM_DATA;
//
// Information structure for window
//
typedef struct {
  GUI_ANIM_HANDLE hAnim;
  ANIM_DATA       Data;
  int             ActiveItem;
} WINDOW_DATA;

//
// Some static data
//
static GUI_ANIM_HANDLE _hAnim;
static ANIM_DATA       _Data;
static WINDOW_DATA     _aDataWindow;
static int             _DoAnimation;
static int             _SwitchDrawing;

/*********************************************************************
*
*       _AnimSwipeInOut
*/
static void _AnimSwipeInOut(GUI_ANIM_INFO * pInfo, void * pVoid) {
  int xPos;
  int yPos;
  int xSize;
  int ySize;
  
  GUI_USE_PARA(pVoid);
  //
  // Calculate a new y position and set the window properly
  //
  if (_Data.Dir) {
    yPos = ((262 * pInfo->Pos) / GUI_ANIM_RANGE);
  } else {
    yPos = 262 - ((262 * pInfo->Pos) / GUI_ANIM_RANGE);
  }
  xPos  = WM_GetWindowOrgX(_Data.hWin);
  xSize = WM_GetWindowSizeX(_Data.hWin); 
  ySize = WM_GetWindowSizeY(_Data.hWin); 
  WM_SetWindowPos(_Data.hWin, xPos, yPos, xSize, ySize);
}

/*********************************************************************
*
*       _AnimMoveWindows
*/
static void _AnimMoveWindows(GUI_ANIM_INFO * pInfo, void * pVoid) {
  int xPos;
  int yPos;
  int xSize;
  int ySize;
  ANIM_DATA * pData;
  
  pData = (ANIM_DATA *) pVoid;
  //
  // Calculate a new x position and set the window properly
  //
  if (pData->Dir) {
    xPos = (LCD_GetXSize() / 2) + (((LCD_GetXSize() / 2) * pInfo->Pos) / GUI_ANIM_RANGE);
  } else {
    xPos = (LCD_GetXSize() - ((LCD_GetXSize() / 2) * pInfo->Pos) / GUI_ANIM_RANGE);
  }
  yPos = WM_GetWindowOrgY(pData->hWin);
  xSize = WM_GetWindowSizeX(pData->hWin); 
  ySize = WM_GetWindowSizeY(pData->hWin); 
  WM_SetWindowPos(pData->hWin, xPos, yPos, xSize, ySize);
}

/*********************************************************************
*
*       _AnimExec
*/
static void _AnimExec(GUI_ANIM_HANDLE * pAnim, ANIM_DATA * pData) {
  while (GUI_ANIM_Exec(*pAnim) == 0) {
    GUI_Delay(5);
  }
  //
  // Clean up after the animation has been completed
  //
  pData->Dir = (pData->Dir) ? 0 : 1;
  GUI_ANIM_Delete(*pAnim);
  *pAnim = 0;
}

/*********************************************************************
*
*       _CreateAnim
*/
static void _CreateAnim(GUI_ANIM_HANDLE * pAnim, ANIM_DATA * pData, GUI_ANIMATION_FUNC * pfAnim) {
  if (*pAnim == 0) {
    *pAnim = GUI_ANIM_Create(300, 10, pData, 0);
    GUI_ANIM_AddItem(*pAnim, 10, 300, ANIM_ACCEL, pData, pfAnim);
    GUI_ANIM_Start(*pAnim);
  }
}

/*********************************************************************
*
*       _cbBk
*/
static void _cbBk(WM_MESSAGE * pMsg) {
  switch (pMsg->MsgId) {
  case WM_PAINT:
    GUI_DrawBitmap(&BM_BACKGROUND, 0, 0);
    break;
  default:
    WM_DefaultProc(pMsg);
  }
}

/*********************************************************************
*
*       _cbWindows
*/
static void _cbWindows(WM_MESSAGE * pMsg) {
  GUI_RECT   Rect;
  GUI_RECT   TRect;
  int        NCode;
  static int Index;

  switch (pMsg->MsgId) {
  case WM_PAINT:
    WM_GetClientRect(&Rect);
    //
    // Draw a Bitmap as background
    //
    GUI_DrawBitmap(&BM_BACKGROUND_WIN, 0, 0);
    //
    // Just draw something if an item has been selected
    //
    if (_aDataWindow.ActiveItem > 0) {
      //
      // Just draw on a switch of content
      //
      if (_SwitchDrawing) {
        Index = _aDataWindow.ActiveItem - ID_SWIPELIST_ITEM_0;
      }
      GUI_EnableAlpha(1);
      GUI_DrawGradientH(Rect.x0 + 1, Rect.y0 + BM_SEPARATOR.YSize, Rect.x1 - 2, Rect.y0 + BM_SEPARATOR.YSize + 10, GUI_TRANSPARENT, _aItemInfo[Index].Color);
      GUI_EnableAlpha(0);
      //
      // Set text color and mode
      //
      GUI_SetTextMode(GUI_TM_TRANS);
      GUI_SetColor(COLOR_WHITE);
      //
      // If we have a pointer to a headline text, draw it
      //
      if (_aItemInfo[Index].pHeadline) {
        GUI_SetFont(&FONT_BOLD);
        TRect.x0 = Rect.x0 + 10;
        TRect.y0 = Rect.y0;
        TRect.x1 = BM_SEPARATOR.XSize;
        TRect.y1 = BM_SEPARATOR.YSize;
        GUI_DispStringInRect(_aItemInfo[Index].pHeadline, &TRect, GUI_TA_LEFT | GUI_TA_VCENTER);
      }
      //
      // Draw the proper icon
      //
      if (_aItemInfo[Index].pBitmap) {
        GUI_DrawBitmap(_aItemInfo[Index].pBitmap, Rect.x0 + 10, Rect.y0 + BM_SEPARATOR.YSize + 5);
      }
      //
      // If we have a pointer to a description text, draw it
      //
      if (_aDescription[Index]) {
        GUI_SetFont(&FONT_REG);
        TRect.y0 += _aItemInfo[Index].pBitmap->YSize + BM_SEPARATOR.YSize + 10;
        TRect.x1 = Rect.x1 - 10;
        TRect.y1 = Rect.y1 - 20;
        GUI_DispStringInRect(_aDescription[Index], &TRect, GUI_TA_LEFT | GUI_TA_TOP);
      }
    }
    break;
  case WM_NOTIFY_PARENT:
    //
    // If the button gets released we start an animation
    //
    NCode = pMsg->Data.v;
    switch(NCode) {
    case WM_NOTIFICATION_RELEASED:
      if (_aDataWindow.Data.Dir) {
        if (_aDataWindow.hAnim == 0) {
          _CreateAnim(&_aDataWindow.hAnim, &_aDataWindow.Data, _AnimMoveWindows);
          _AnimExec(&_aDataWindow.hAnim, &_aDataWindow.Data);
          //
          // The window isn't visible any longer, no item active
          //
          _aDataWindow.ActiveItem = -1;
        }
      }
      break;
    }
    break;
  default:
    WM_DefaultProc(pMsg);
  }
}

/*********************************************************************
*
*       _cbWin
*/
static void _cbWin(WM_MESSAGE * pMsg) {
  GUI_RECT   Rect;
  int        Id;
  int        NCode;
  int        ReleasedItem;
  int        ActiveWindow;
  
  switch (pMsg->MsgId) {
  case WM_PAINT:
    //
    // Draw a thin black frame around the SWIPELIST
    //
    WM_GetClientRect(&Rect);
    GUI_SetColor(GUI_BLACK);
    GUI_AA_DrawRoundedRect(Rect.x0, Rect.y0, Rect.x1, Rect.y1, 5);
    break;
  case WM_NOTIFY_PARENT:
    Id    = WM_GetId(pMsg->hWinSrc);
    NCode = pMsg->Data.v;
    switch(Id) {
    //
    // If the button gets released we start an animation
    //
    case ID_BUTTON_0:
      switch(NCode) {
      case WM_NOTIFICATION_CLICKED:
        break;
      case WM_NOTIFICATION_RELEASED:
        _CreateAnim(&_hAnim, &_Data, _AnimSwipeInOut);
        break;
      }
      break;
    case ID_SWIPELIST_0:
      switch (NCode) {
      //
      // An item has been reeleased
      //
      case WM_NOTIFICATION_RELEASED:
        //
        // Receive the ID of the item which has been released
        //
        ReleasedItem = SWIPELIST_GetReleasedItem(pMsg->hWinSrc);
        ActiveWindow = SWIPELIST_GetItemUserData(pMsg->hWinSrc, ReleasedItem);
        //
        // if it is different to the active window or not present
        //
        if ((_aDataWindow.ActiveItem != ActiveWindow) || (_aDataWindow.Data.Dir == 0)) {
          _DoAnimation = 1;
          //
          // If it is not displayed already, create an animation
          //
          if (_aDataWindow.Data.Dir == 0) {
            _CreateAnim(&_aDataWindow.hAnim, &_aDataWindow.Data, _AnimMoveWindows);
          }
          //
          // Remeber the active window
          //
          _aDataWindow.ActiveItem = ActiveWindow;
        }
        break;
      }
    break;
    }
  default:
    WM_DefaultProc(pMsg);
  }
}

/*********************************************************************
*
*       _OwnerDraw
*/
static int _OwnerDraw(const WIDGET_ITEM_DRAW_INFO * pDrawItemInfo) {
  GUI_COLOR Color;
  GUI_RECT  rInside;
  int       Height;
  int       Width;
    
  //
  // Distinguish between different commands
  //
  switch (pDrawItemInfo->Cmd) {
  case WIDGET_ITEM_GET_XSIZE:
    WM_GetInsideRectEx(pDrawItemInfo->hWin, &rInside);
    Width = rInside.x1;
    return Width;
  case WIDGET_ITEM_GET_YSIZE:
    Height = GUI_GetFontDistY() + 40;
    return Height;
  case WIDGET_ITEM_DRAW_FRAME:
    //
    // Skip this part, we do not want to draw this one
    //
    break;
  case WIDGET_ITEM_DRAW:
    //
    // Skip this part, we do not want to draw this one
    //
    break;
  case WIDGET_ITEM_DRAW_SEP:
    //
    // Skip this part, we do not want to draw this one
    //
    break;
  case WIDGET_ITEM_DRAW_TEXT:
    //
    // Just set a text mode but let the default owner draw routine handle the rest
    //
    GUI_SetTextMode(GUI_TM_TRANS);
    SWIPELIST_OwnerDraw(pDrawItemInfo);
    break;
  case WIDGET_ITEM_DRAW_BITMAP:
    //
    // Skip this part, we do not want to draw this one
    //
    break;
  case WIDGET_ITEM_DRAW_BACKGROUND:
    //
    // Handle drawing of the background of the items
    //
    switch (pDrawItemInfo->ItemIndex) {
    case SWIPE_ITEM_ID0:
      //
      // the first entry in the SWIPELIST needs special treatment
      //
      GUI_SetColor(GUI_DARKGRAY);
      GUI_DrawLine(pDrawItemInfo->x0, pDrawItemInfo->y0, pDrawItemInfo->x1, pDrawItemInfo->y0);
    case SWIPE_ITEM_ID4:
    case SWIPE_ITEM_ID6:
    case SWIPE_ITEM_ID15:
      //
      // Case 0, 4, 8 and 12 are the separator items, here we handle their drawing
      //
      GUI_SetColor(GUI_BLACK);
      GUI_FillRect(pDrawItemInfo->x0, pDrawItemInfo->y1 - 3, pDrawItemInfo->x1, pDrawItemInfo->y1);
      GUI_DrawBitmap(&BM_SEPARATOR, pDrawItemInfo->x0, pDrawItemInfo->y0);
      break;
    case SWIPE_ITEM_ID1:
    case SWIPE_ITEM_ID5:
    case SWIPE_ITEM_ID7:
    case SWIPE_ITEM_ID16:
      //
      // These cases are the entries below the seperators, those need special treatment as well
      //
      if (pDrawItemInfo->ItemIndex == SWIPELIST_GetSelItem(pDrawItemInfo->hWin)) {
        Color = COLOR_GREEN;
      } else {
        Color = COLOR_BLUE;
      }
      GUI_SetColor(Color);
      GUI_FillRect(pDrawItemInfo->x0, pDrawItemInfo->y0 + 1, pDrawItemInfo->x1, pDrawItemInfo->y1);
      GUI_DrawGradientV(pDrawItemInfo->x0, pDrawItemInfo->y0,
                        pDrawItemInfo->x1, pDrawItemInfo->y1 - ((pDrawItemInfo->y1 - pDrawItemInfo->y0) / 2), GUI_BLACK, Color);
      break;
    default:
      //
      // All other items are getting drawn the same way
      //
      if (pDrawItemInfo->ItemIndex == SWIPELIST_GetSelItem(pDrawItemInfo->hWin)) {
        Color = COLOR_GREEN;
      } else {
        Color = COLOR_BLUE;
      }
      GUI_SetColor(Color);
      GUI_FillRect(pDrawItemInfo->x0, pDrawItemInfo->y0, pDrawItemInfo->x1, pDrawItemInfo->y1);
      break;
    }
    break;
  default:
    //
    // Anything we do not catch in this routine gets handled by the default owner draw
    //
    return SWIPELIST_OwnerDraw(pDrawItemInfo);
  }
  return 0;
}

/*********************************************************************
*
*       _CreateWindows
*/
static void _CreateWindows(WM_HWIN hParent) {
  int     xSize;
  int     ySize;
  int     xPos;
  int     yPos;
  
  GUI_USE_PARA(hParent);
  xSize = BM_SEPARATOR.XSize + 2;//LCD_GetXSize() / 2 + 5;
  ySize = LCD_GetYSize() - 20;
  xPos  = LCD_GetXSize() / 2;
  yPos  = 10;
  _aDataWindow.Data.hWin  = WM_CreateWindow(xPos, yPos, xSize, ySize, WM_CF_SHOW | WM_CF_HASTRANS, _cbWindows, 0);
  _aDataWindow.Data.Dir   = 1;
  _aDataWindow.ActiveItem = ID_SWIPELIST_ITEM_0;
  _SwitchDrawing = 1;
}

/*********************************************************************
*
*       MainTask
*/
void MainTask(void) {
  WM_HWIN _hSwipelist;
  WM_HWIN hWin;
  int     xSize;
  int     ySize;
  int     xPos;
  int     yPos;
  int     i;

#ifdef WIN32
  WM_SetCreateFlags(WM_CF_MEMDEV);
#endif
  WM_MOTION_Enable(1);
  WM_MULTIBUF_Enable(1);
  GUI_Init();
  //
  // Set a callback for the background window
  //
  WM_SetCallback(WM_HBKWIN, _cbBk);
  //
  // Create a window which contains the swipelist
  //
  xPos  = 10;
  yPos  = 10;
  xSize = LCD_GetXSize() / 2 - 20;
  ySize = LCD_GetYSize();
  hWin  = WM_CreateWindowAsChild(xPos, yPos, xSize, ySize, WM_HBKWIN, WM_CF_SHOW | WM_CF_HASTRANS, _cbWin, 0);
  //
  // Attach SWIPELIST to the window
  //
  xPos  = 1;
  yPos  = 1;//12;
  xSize = WM_GetWindowSizeX(hWin) - 2;
  ySize = WM_GetWindowSizeY(hWin) - 10;
  _hSwipelist = SWIPELIST_CreateEx(xPos, yPos, xSize, ySize, hWin, WM_CF_SHOW | WM_CF_HASTRANS, 0, ID_SWIPELIST_0);
  WM_MOTION_SetMoveable(_hSwipelist, WM_CF_MOTION_Y, 1);
  //
  // Configure SWIPELIST
  //
  SWIPELIST_SetOwnerDraw(_hSwipelist, _OwnerDraw);
  SWIPELIST_SetFont(_hSwipelist, SWIPELIST_FI_SEP_ITEM, &FONT_BOLD);
  SWIPELIST_SetFont(_hSwipelist, SWIPELIST_FI_ITEM_HEADER, &FONT_REG);
  SWIPELIST_SetFont(_hSwipelist, SWIPELIST_FI_ITEM_TEXT, &FONT_REG);
  SWIPELIST_SetDefaultSepSize(1);
  SWIPELIST_SetDefaultSepColor(GUI_BLACK);
  SWIPELIST_SetTextColor(_hSwipelist, SWIPELIST_CI_ITEM_HEADER_UNSEL, COLOR_WHITE);
  SWIPELIST_SetTextColor(_hSwipelist, SWIPELIST_CI_ITEM_HEADER_SEL, COLOR_WHITE);
  SWIPELIST_SetTextColor(_hSwipelist, SWIPELIST_CI_ITEM_TEXT_UNSEL, COLOR_WHITE);
  SWIPELIST_SetTextColor(_hSwipelist, SWIPELIST_CI_ITEM_TEXT_SEL, COLOR_WHITE);
  SWIPELIST_SetTextColor(_hSwipelist, SWIPELIST_CI_SEP_ITEM_TEXT, COLOR_WHITE);
  //
  // Fill ANIM_DATA structure
  //
  _Data.Dir  = 0;
  _Data.hWin = hWin;
  //
  // Add Items to the SWIPELIST
  //
  SWIPELIST_AddSepItem(_hSwipelist, _aTextSeparator[SWIPE_SEP_INDEX0], SWIPE_SEPERATOR_SIZE);  // Dev Software
  for (i = 0; i < 3; i++) {
    SWIPELIST_AddItem(_hSwipelist, _aTextHeader[i], SWIPE_ITEM_SIZE);                          // Text to shown under the menu entry above
    SWIPELIST_SetItemUserData(_hSwipelist, i + 1, ID_SWIPELIST_ITEM_0 + i);
  }
  SWIPELIST_AddSepItem(_hSwipelist, _aTextSeparator[SWIPE_SEP_INDEX1], SWIPE_SEPERATOR_SIZE);  // Debug Probes
  for (; i < 4; i++) {
    SWIPELIST_AddItem(_hSwipelist, _aTextHeader[i], SWIPE_ITEM_SIZE);                          // Text to shown under the menu entry above
    SWIPELIST_SetItemUserData(_hSwipelist, i + 2, ID_SWIPELIST_ITEM_0 + i);
  }
  SWIPELIST_AddSepItem(_hSwipelist, _aTextSeparator[SWIPE_SEP_INDEX2], SWIPE_SEPERATOR_SIZE);  // Private
  for (; i < 12; i++) {
    SWIPELIST_AddItem(_hSwipelist, _aTextHeader[i], SWIPE_ITEM_SIZE);                          // Text to shown under the menu entry above
    SWIPELIST_SetItemUserData(_hSwipelist, i + 3, ID_SWIPELIST_ITEM_0 + i);
  }
  SWIPELIST_AddSepItem(_hSwipelist, _aTextSeparator[SWIPE_SEP_INDEX3], SWIPE_SEPERATOR_SIZE);  // System
  for (; i < 13; i++) {
    SWIPELIST_AddItem(_hSwipelist, _aTextHeader[i], SWIPE_ITEM_SIZE);                          // Text to shown under the menu entry above
    SWIPELIST_SetItemUserData(_hSwipelist, i + 4, ID_SWIPELIST_ITEM_0 + i);
  }
  _CreateWindows(WM_HBKWIN);
  //
  // Stay alive loop
  //
  while (1) {
    //
    // If an animation has been created, process it
    //
    if (_hAnim) {
      _AnimExec(&_hAnim, &_Data);
    }
    //
    // Handle Info window animation
    //
    if (_DoAnimation) {  // Animation required ?
      //
      // If it is already present
      //
      if (_aDataWindow.Data.Dir) {
        _SwitchDrawing = 0;
        _CreateAnim(&_aDataWindow.hAnim, &_aDataWindow.Data, _AnimMoveWindows);  // Create an animation for moving out the window
        _AnimExec(&_aDataWindow.hAnim, &_aDataWindow.Data);                      // Execute the animation
        _CreateAnim(&_aDataWindow.hAnim, &_aDataWindow.Data, _AnimMoveWindows);  // Create an animation for moving in again
      }
      //
      // If no window is present but an animation has been created move in the window
      //
      if (_aDataWindow.hAnim) {
        _SwitchDrawing = 1;
        _AnimExec(&_aDataWindow.hAnim, &_aDataWindow.Data);
      }
      //
      // Animation has been processed, reset variable
      //
      _DoAnimation = 0;
    }
    GUI_Delay(50);
  }
}
